package cn.sunshine.framework.context.support;

import cn.sunshine.framework.beans.BeansException;
import cn.sunshine.framework.beans.factory.ConfigurableListableBeanFactory;
import cn.sunshine.framework.beans.factory.config.BeanFactoryPostProcessor;
import cn.sunshine.framework.beans.factory.config.BeanPostProcessor;
import cn.sunshine.framework.context.ApplicationEvent;
import cn.sunshine.framework.context.ApplicationListener;
import cn.sunshine.framework.context.ConfigurableApplicationContext;
import cn.sunshine.framework.context.event.ApplicationEventMulticaster;
import cn.sunshine.framework.context.event.ContextRefreshedEvent;
import cn.sunshine.framework.context.event.SimpleApplicationEventMulticaster;
import cn.sunshine.framework.core.io.DefaultResourceLoader;

import java.util.Collection;
import java.util.Map;

/**
 * Abstract implementation of the {@link cn.sunshine.framework.context.ApplicationContext}
 * interface. Doesn't mandate the type of storage used for configuration; simply
 * implements common context functionality. Uses the Template Method design pattern,
 * requiring concrete subclasses to implement abstract methods.
 *
 * <p>抽象应用上下文, 定义共有的抽象成员以及固定算法, 具体实现交由子类
 * <p>DefaultResourceLoader: 注册需要使用 资源加载器先加载资源,
 * <p>ConfigurableApplicationContext: 规范接口
 * @Author Mokairui
 * @Since 2021/12/11
 */
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {

    public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";

    private ApplicationEventMulticaster applicationEventMulticaster;

    @Override
    public void refresh() throws BeansException {
        // 1. 创建 BeanFactory, 并加载 BeanDefinition
        refreshBeanFactory();

        // 2. 获取 BeanFactory
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();

        // 3. 添加 ApplicationContextAwareProcessor, 让继承自 ApplicationContextAware 的 Bean 对象都能感知所属的 ApplicationContext
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

        // 4. 在 Bean 实例化之前, 执行 BeanFactoryProcessor (Invoke factory registered as beans in the context.)
        invokeBeanFactoryPostProcessor(beanFactory);

        // 5. BeanPostProcessor 需要提前于其他 Bean 对象实例化之前执行注册操作
        registerBeanProcessors(beanFactory);

        // 6. 初始化事件发布者
        initApplicationEventMulticaster();

        // 7. 注册事件监听器
        registerListeners();

        // 8. 提前实例化单例 Bean 对象
        beanFactory.preInstantiateSingletons();

        // 9. 发布容器刷新完成事件
        finishRefresh();

    }

    private void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, applicationEventMulticaster);
    }

    private void registerListeners() {
        Collection<ApplicationListener> applicationListeners = getBeansOfType(ApplicationListener.class).values();
        for (ApplicationListener listener : applicationListeners) {
            applicationEventMulticaster.addApplicationListener(listener);
        }
    }

    private void finishRefresh() {
        publishEvent(new ContextRefreshedEvent(this));
    }

    protected abstract void refreshBeanFactory() throws BeansException;

    protected abstract ConfigurableListableBeanFactory getBeanFactory();

    private void invokeBeanFactoryPostProcessor(ConfigurableListableBeanFactory beanFactory) {
        Map<String, BeanFactoryPostProcessor> beanFactoryProcessorMap = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
        for (BeanFactoryPostProcessor beanFactoryPostProcessor : beanFactoryProcessorMap.values()) {
            // 执行用户自定义扩展的 BeanFactoryProcessor
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        }
    }

    private void registerBeanProcessors(ConfigurableListableBeanFactory beanFactory) {
        Map<String, BeanPostProcessor> beanPostProcessorMap = beanFactory.getBeansOfType(BeanPostProcessor.class);
        for (BeanPostProcessor beanPostProcessor : beanPostProcessorMap.values()) {
            // 将用户扩展的 BeanPostProcessor 加入 processor 容器, 在初始化 bean 时(createBean), 会调用
            beanFactory.addBeanPostProcessor(beanPostProcessor);
        }
    }

    @Override
    public void publishEvent(ApplicationEvent event) {
        applicationEventMulticaster.multicastEvent(event);
    }

    @Override
    public Object getBean(String name) throws BeansException {
        return getBeanFactory().getBean(name);
    }

    @Override
    public Object getBean(String name, Object... args) throws BeansException {
        return getBeanFactory().getBean(name, args);
    }

    @Override
    public <T> T getBean(String name, Class<T> requireType) throws BeansException {
        return getBeanFactory().getBean(name, requireType);
    }

    @Override
    public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
        return getBeanFactory().getBeansOfType(type);
    }

    @Override
    public String[] getBeanDefinitionNames() {
        return getBeanFactory().getBeanDefinitionNames();
    }

    // ConfigurableApplicationContext
    @Override
    public void registerShutdownHook() {
        Runtime.getRuntime().addShutdownHook(new Thread(this::close));
    }

    // ConfigurableApplicationContext
    @Override
    public void close() {
        /*
         * getBeanFactory() -> ConfigurableListableBeanFactory
         * destroySingletons() -> 规范: ConfigurableBeanFactory 是 ConfigurableListableBeanFactory 子类
         * destroySingletons() -> 具体实现: DefaultSingletonBeanRegistry
         *
         * 为什么在 ConfigurableBeanFactory 定义的规范, 可以在 DefaultSingletonBeanRegistry 中实现?
         * 实际上有一个类 AbstractBeanFactory 继承了 DefaultSingletonBeanRegistry 类, 实现了 ConfigurableBeanFactory 接口
         * 这个是不是像类适配器模式? 因为实现了 ConfigurableBeanFactory 接口所以要求有他的 destroySingletons 规范,
         * 而 getBeanFactory() 返回的是他的子接口所以是可以调用到 destroySingletons() 方法的,
         * 那如何找到他具体的实现的呢?
         * 实际上 getBeanFactory() 返回的接口只有一个实现类: DefaultListableBeanFactory
         * 而这个子类最终又是 DefaultSingletonBeanRegistry 的子类, 子类没有方法会去父类找实现, 所以才能正常执行.
         */
        getBeanFactory().destroySingletons();
    }
}
